package agents.persona;

import objects.centrotrabajo.*;
import objects.residencia.*;

import repast.simphony.context.Context;
import repast.simphony.space.grid.*;
import repast.simphony.util.ContextUtils;


/*********************************************************************************************************************
 * Estrucutra generica de los Agentes Personas. El tipo "Abstract" no permite que se creee una Persona general
 * dentro del modelo, sino que se debe realizar la implementacion de Personas especificas que hereden de esta
 * la estructura y el comportamiento para luego implementarlos de manera particular.
 * 
 * @author Henry Alberto
 * @author Fedrico Lievano
 */

public abstract class Persona {

	protected boolean empleado; 
	protected Residencia residencia;
	protected CentroTrabajo centroTrabajo;
	protected double salario;
	protected double ahorro;
	protected double gastos;
	protected double distancia;
	protected double costoTransporte;
	
	
	/*******************************************************************************************************************
	 * Constructores  de la Super Clase. 
	 */
	public Persona(){
		empleado = false; 
		residencia = null;
		centroTrabajo = null;
		salario = 0;
		ahorro = 0;
		gastos = 0;
		distancia = 0;
		costoTransporte = 0;
	}	
		
	/*******************************************************************************************************************
	 * Cuando el Empleador asigna un trabajo a X Persona, se ejecuta este metodo, asignandole dicho lugar de trabajo y 
	 * un salario a dos de las propiedades de cada Agente Persona. Tambien se cambia la propiedad empleado, que indica 
	 * si esta o no trabajando.
	 * 
	 * Recibe como argumentos, el salario que depende del tipo de Centro de Trabajo y una referencia a dicho centro.
	 */
	public void Emplearce(CentroTrabajo a, long salario){
		this.centroTrabajo = a;
		this.empleado = true;
		this.salario = salario;
	}
	
	/*******************************************************************************************************************
	 * Este comportamiento actualiza el Ahorro de cada persona en base a sus ingresos y gastos para cada iteraccion.
	 */
	public void stepAhorro(){
		
		ahorro = ahorro + salario;
		
		if(residencia == null)
			ahorro = ahorro - gastos;
		else
			ahorro = ahorro - costoTransporte;
		
	}
	

	/*******************************************************************************************************************
	 * Cuando un Agente Constrcutor edifica una Residencia, se genera una oferta de viviendas donde el Agente Persona
	 * reacciona comprando dicha Residencia. Este metodo permite tener referencia en cada Agente Persona de la 
	 * Residencia donde esta viviendo. Tambien actualiza propiedades como la distancia, el costo de transporte y gastos.
	 */
	public void setResidencia(Residencia residencia){
		
		this.residencia = residencia; //Se almacena la referencia de la Residencia donde vive

		Context context = ContextUtils.getContext(this);

		Grid patch = (Grid) context.getProjection("Medellin Grid");

		GridPoint pointR = patch.getLocation(this.residencia); //Se busca la residencia dentro del Grid
		GridPoint pointC = patch.getLocation(this.centroTrabajo); //Se busca el centro donde trabaja dentro del Grid
		
		int xR = pointR.getX();   //Coordenada X de la residencia
		int yR = pointR.getY();	  //Coordenada Y de la residencia
		
		int xC = pointC.getX();   //Coordenada X del centro de trabajo
		int yC = pointC.getY();   //Coordenada X del centro de trabajo
		
		this.gastos = 0;  //Este tipo de gatos(Arriendo) ya no tienen valides dentro de este Agente Persona 
		
		//Se calcula y almacena la distancia desde la Residencia hasta el Centro donde trabaja
		this.distancia = Math.sqrt(Math.pow((xR-xC),2) + Math.pow(yR-yC, 2)); 
		
		this.costoTransporte = 1 * this.distancia; //Se tiene calcula el costo de transporte en base a la distancia.
	}
	
	/*******************************************************************************************************************
	 * Este metodo se comporta igual que el anterior solo que este solo se ejecuta para construir las consdiciones 
	 * inciales del modelo.
	 */
	public void setResidenciaInicial(Residencia residencia, double distancia){
		
		this.residencia = residencia; //Se almacena la referencia de la Residencia donde vive

		this.gastos = 0;  //Este tipo de gatos(Arriendo) ya no tienen valides dentro de este Agente Persona 
		
		//Se calcula y almacena la distancia desde la Residencia hasta el Centro donde trabaja
		this.distancia = distancia; 
		
		this.costoTransporte = 1 * this.distancia; //Se tiene calcula el costo de transporte en base a la distancia.
	}
	
	/*****************************************************************************************************************
	 * Algunas funciones Gets y Sets que permiten manipular las propiedades de cada Agente Persona 
	 */
	public Residencia getResidencia(){
		return residencia;
	}
	
	public double getAhorro(){
		return ahorro;
	}
	
	/*****************************************************************************************************************
	 * Estas funciones permiten identificar si el Agente Persona esta o no empleada. 
	 * True: Esta trabajando
	 * False: No esta trabajando
	 */
	public boolean isEmpleada(){
		return empleado;
	}
	
	
	/*****************************************************************************************************************
	 * Estas funciones permiten identificar el tipo de persona al cual corresponde determinada instancia en el modelo. 
	 */
	public boolean isRica(){
		return false;
	}
	
	public boolean isPobre(){
		return false;
	}

}
